﻿using System;
using System.Threading;
using Amazon.SimpleDB;
using Amazon.SimpleDB.Model;
using ICommonLibrary.Scheduler;
using ICommonLibrary.Service;
using NLog;

namespace ICommonLibrary.Aws {

    public class AmazonSimpleDbService : ServiceBase {

        public ISchedulerService SchedulerService { get; set; }

        public AwsAccount AwsAccount { get; set; }

        public delegate void ExceptionHandler(Exception e);

        public event ExceptionHandler InitExceptionHandler;

        public string[] Domains { get; set; }

        private readonly EventWaitHandle _readyLock = new ManualResetEvent(false);


        private AmazonSimpleDB _service;

        public AmazonSimpleDbService() {
        }

        protected override void OnInit() {
            Asserts.NotNull(SchedulerService, "Scheduler service is not in place");
            Asserts.NotNull(AwsAccount, "Aws account is not provided.");

            _service = Amazon.AWSClientFactory.CreateAmazonSimpleDBClient(AwsAccount.AccessKey, AwsAccount.SecretAccessKey);
            
            /**
             * The first request to Amazon is slow. Performing an operation ensure the domain is created
             * can consume the first request.
             */
            SchedulerService.Schedule(Init, Domains, TimeSpan.FromSeconds(1));
        }

        protected override void OnStart() {
        }

        protected override void OnStop() {
        }

        protected override void OnDestroy() {
        }

        public DeleteAttributesResponse DeleteAttributes(DeleteAttributesRequest request) {
            _readyLock.WaitOne();
            return _service.DeleteAttributes(request);
        }

        public PutAttributesResponse PutAttributes(PutAttributesRequest request) {
            _readyLock.WaitOne();
            return _service.PutAttributes(request);
        }

        public SelectResponse Select(SelectRequest request) {
            _readyLock.WaitOne();
            request.WithConsistentRead(true);
            return _service.Select(request);
        }

        private void Init(object domainsObj) {
            for (int i = 1; i <= 3; i++) {
                try {
                    foreach (var domain in (string[])domainsObj) {
                        _service.CreateDomain(new CreateDomainRequest().WithDomainName(domain));
                    }
                }
                catch(Exception e) {
                    // sometimes it happens due to 'Maximum number of retry attempts reached : 3', in which case, the program should try again.
                    if (i == 3) {
                        LogManager.GetCurrentClassLogger().ErrorException("CreateDomain failed: " + e.Message, e);
                        if (InitExceptionHandler != null) {
                            InitExceptionHandler(e);
                        }
                    }
                    else {
                        Thread.Sleep(TimeSpan.FromSeconds(10));
                    }
                }
            }
            _readyLock.Set();
        }

    }
}